#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/time.h>

/********************************************************/
/** Trabalho 1 - Sistemas Distribuídos (SSC-0642)      **/
/** USP São Carlos - Prof. Julio Cezar Estrella        **/
/** Grupo 06:                                          **/
/** Ana Elisa Siena - NoUSP 7126563                    **/
/** Larissa Zimmermann - NoUSP 7126879                 **/
/********************************************************/

/********************* NIVEL 1 **************************/

/********************************************************/
/** Função: randomArray                                **/
/** O que faz: cria um vetor aleatório                 **/
/** Parâmetros: *array - um vetor                      **/
/**              size - inteiro com o tamanho do vetor **/
/** Return: nenhum (função void)                       **/
/********************************************************/

void randomArray(int *array, int size){
    int i, aux;

    srand (time(NULL));

    for(i = 0; i < size; i++){
        aux = rand()%9999;
        if(aux!= 0)
            array[i] = aux;
    }
}

/********************************************************/
/** Função: showArray                                  **/
/** O que faz: imprime um vetor                        **/
/** Parâmetros:                                        **/
/**       array - um vetor                             **/
/**       sizeOsArray - inteiro com o tamanho do vetor **/
/** Return: nenhum (função void)                       **/
/********************************************************/

void showArray(int *array, int sizeOfArray){
    int i;

    for(i = 0; i < sizeOfArray; i++){
		printf("%d ", array[i]);
    }

    printf("\nQuantidade de elementos: %d.\n", i);
}

/********************************************************/
/** Função: get_time                                   **/
/** O que faz: coleta o horário atual                  **/
/** Parâmetros: nenhum                                 **/
/** Return: retorna o tempo em double                  **/
/** Fonte: André Cunha (andre.lv.cunha@gmail.com)      **/
/********************************************************/

double get_time()
{
    struct timeval tv;

    gettimeofday(&tv, NULL);

    double ret = tv.tv_usec;

    //Convert from micro seconds (10^-6) to milliseconds (10^-3)
    ret /= 1000;

    //Adds the seconds (10^0) after converting them to milliseconds (10^-3)
    ret += (tv.tv_sec * 1000);

    return ret;
}

/********************************************************/
/** Função: main                                       **/
/** O que faz: main do programa                        **/
/** Parâmetros: porta do cliente 1, porta do cliente 2 **/
/** Return: retorna 0                                  **/
/********************************************************/

int main(int argc, char *argv[ ])
{
	//Constantes
	int Array_Size_1 = 125, Array_Size_4 = 1000, Size_Buffer = 10, sin_size, true = 1;

	//Variaveis de contagem de tempo
	double tStart_C_S, tEnd_C_S, tStart_Problem, tEnd_Problem;
	double tElapsed_C_S, tElapsed_Problem, tElapsed_C_S_2;

	//Variáveis em geral
	struct sockaddr_in server_addr, server_addr_s, client_addr;
	char server_name[512], recv_data[1024];

	//Variáveis relativas ao primeiro socket
	int port_client;
	int sock;
	struct hostent *host;
	int array[Array_Size_1];
	int connection;

	//Variáveis relativas ao segundo socket
	int port_client_second;
	int sock_second;
	struct hostent *host_client_second;
	int array_recv[Array_Size_4];
	int rc;

    //portas dos clientes
	strcpy(server_name, argv[1]);
	port_client = atoi(argv[2]);
	port_client_second = atoi(argv[3]);

	tStart_Problem = get_time();

	//Cria o vetor aleatório
	randomArray(array, Array_Size_1);

	/* Cliente 1 - que envia os vetores de 125 valores aleatórios */

	host = gethostbyname(server_name);

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1 || host == NULL)
	{
		perror("Erro de socket ou host no nivel 1!!.\n");
		exit(1);
	}

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port_client);
	server_addr.sin_addr = *((struct in_addr *)host->h_addr);
	bzero(&(server_addr.sin_zero),8);

	tStart_C_S = get_time();
	connection = connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
	send(sock, array, sizeof(int)*Array_Size_1, 0);
	tEnd_C_S = get_time();
    tElapsed_C_S = tEnd_C_S - tStart_C_S;

    tStart_C_S = get_time();
    recv(sock, array_recv, sizeof(int)*Array_Size_4, MSG_WAITALL);
    tEnd_C_S = get_time();
    tElapsed_C_S_2 = tEnd_C_S - tStart_C_S;

    printf("\n\nNIVEL 1\n\n");

	//Imprimi o vetor aletatório de 125 valores
	printf("--------------------Vetor original:\n");
	showArray(array, Array_Size_1);

    //Imprimi o vetor de 1000 dados ordenados
	printf("--------------------Vetor ordenado:\n");
	showArray(array_recv, Array_Size_4);

	tEnd_Problem = get_time();

	tElapsed_Problem = tEnd_Problem - tStart_Problem;

    //Imprimi os tempos
	printf("Tempos:\n");
	printf("Tempo de comunicacao cliente - servidor (nivel1-nivel2) em milisegundos: %.3lf.\n", tElapsed_C_S);
    printf("Tempo de comunicacao cliente - servidor (nivel4-nivel1) em milisegundos: %.3lf.\n", tElapsed_C_S_2);
	printf("Tempo de ordenacao total em milisegundos: %.3lf.\n", tElapsed_Problem);

	close(sock);

	return 0;
}
